﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Configuration;
using System.Configuration;
using System.IO;
using System.Web.Security;

namespace Rookey.Frame.IMCore
{
	using IO;

	public class ServerImpl
	{
        static ServerImpl m_Instance = new ServerImpl();

		static public ServerImpl Instance
		{
			get { return m_Instance; }
		}

		static ServerImpl()
		{
			Instance.Initialize(HttpContext.Current);
		}

		private ServerImpl()
		{
		}

		string m_BaseDirecotry = String.Empty;
		string _fileRoot;
		string _serviceUrl = "";

		public string BaseDirecotry
		{
			get { return m_BaseDirecotry; }
		}

		public void Initialize(HttpContext context)
		{
			m_BaseDirecotry = context.Server.MapPath("~");
			_fileRoot = GetFileRoot(context);

			_serviceUrl = context.Request.ApplicationPath;
			if (!_serviceUrl.EndsWith("/")) _serviceUrl += "/";
			_serviceUrl += "IM";

			AccountImpl.Instance.Init();
		}

		public void Dispose(HttpApplication app)
		{
		}

		public String GetFileRoot(HttpContext context)
		{
            try
            {
                Configuration config = WebConfigurationManager.OpenWebConfiguration(context.Request.ApplicationPath == "/" ? "/IM" : context.Request.ApplicationPath + "/IM");

                string fileRoot = config.AppSettings.Settings["FileRoot"].Value;

                if (String.IsNullOrEmpty(fileRoot))
                {
                    string path = context.Server.MapPath("~");
                    while (path.EndsWith("\\")) path = path.Substring(0, path.Length - 1);

                    return System.IO.Path.GetDirectoryName(path) + @"\IM\Files";
                }
                else
                {
                    if (!System.IO.Path.IsPathRooted(fileRoot))
                    {
                        string path = context.Server.MapPath("~");
                        while (path.EndsWith("\\")) path = path.Substring(0, path.Length - 1);
                        path += "\\IM";

                        System.IO.Directory.CreateDirectory(System.IO.Path.Combine(path, fileRoot));
                        System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(System.IO.Path.Combine(path, fileRoot));
                        return dir.FullName;
                    }
                    else
                    {
                        return fileRoot;
                    }
                }
            }
            catch { }
            return string.Empty;
		}

		public string GetUserName(HttpContext context)
		{
			if (context.Request.Cookies["IM"] != null)
			{
				return context.Request.Cookies["IM"].Value;
			}
			else
			{
				return String.Empty;
			}
		}

		public void Login(String sessionId, HttpContext context, String user, Nullable<DateTime> expires)
		{
			Login(sessionId, context, user, expires, true);
		}

		public void Login(String sessionId, HttpContext context, String user, Nullable<DateTime> expires, bool startSession)
		{
			HttpCookie cookie = new HttpCookie("IM", user);
			if (expires != null) cookie.Expires = expires.Value;
			context.Response.Cookies.Add(cookie);

			if (startSession) SessionManagement.Instance.GetAccountState(user).NewSession(sessionId);
		}

		public void Logout(HttpContext context)
		{
			HttpCookie cookie = new HttpCookie("IM", "");
			cookie.Expires = DateTime.Now.AddDays(-7);
			context.Response.Cookies.Add(cookie);
		}

		public bool IsPublic(string path)
		{
			string relative = Rookey.Frame.IMCore.IO.Path.GetRelativePath(path);
			string root = Rookey.Frame.IMCore.IO.Path.GetRoot(relative).ToLower();
			return root == "public";
		}

		public string MapPath(string path)
		{
			string relative = Rookey.Frame.IMCore.IO.Path.GetRelativePath(path);
			string[] pns = relative.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

			if (pns.Length > 0 && pns[0].ToLower() == "public")
			{
				return Path.Join(@"\", _fileRoot, "Public", Path.Join(@"\", pns, 1));
			}
			if (pns.Length > 0 && pns[0].ToLower() == "temp")
			{
				return Path.Join(@"\", _fileRoot, "Temp", Rookey.Frame.IMCore.IO.Path.GetUser(path), Path.Join(@"\", pns, 1));
			}
			else
			{
				string user = Rookey.Frame.IMCore.IO.Path.GetUser(path);
				return String.Format(@"{0}\Users\{1}\{2}", _fileRoot, user, Path.Join(@"\", pns, 0));
			}
		}

		public string GetFullPath(HttpContext context, string path)
		{
			string user = Path.GetUser(path);
			return String.IsNullOrEmpty(user) ? String.Format("/{0}/{1}", GetUserName(context), path) : path;
		}

		int RootDirectoryPermission = IOPermission.Read;
		int PublicSubItemsPermission = IOPermission.Read;
		int RootSubItemsPermission = IOPermission.Read | IOPermission.Write;
		int RootPublicSubItemsPermission = IOPermission.Read;

		public void CheckPermission(HttpContext context, string path, int action)
		{
			string relative = Path.GetRelativePath(path);
			string relativeRoot = Path.GetRoot(relative).ToLower();
			if (relativeRoot == "pub" || relativeRoot == "public") return;

			AccountInfo currentUser = ServerImpl.Instance.GetCurrentUser(context);
			string owner = Path.GetUser(path);
			if (String.IsNullOrEmpty(owner)) owner = currentUser.Name;
			AccountInfo ownerInfo = AccountImpl.Instance.GetUserInfo(owner);

			if (ownerInfo.Type == 1 && ownerInfo.ContainsMember(currentUser.Name)) return;

			if (ownerInfo.ID != currentUser.ID) throw new PermissionException();

			if (String.IsNullOrEmpty(relative) && (RootDirectoryPermission & action) != action) throw new PermissionException();

			if (String.Compare(relative, relativeRoot, true) == 0)
			{
				if (relativeRoot == "public")
				{
					if ((RootPublicSubItemsPermission & action) != action) throw new PermissionException();
				}
				else
				{
					if ((RootSubItemsPermission & action) != action) throw new PermissionException();
				}
			}
			else
			{
				if (relativeRoot == "public")
				{
					if ((PublicSubItemsPermission & action) != action) throw new PermissionException();
				}
				else
				{
				}
			}
		}

		public String Version
		{
			get { return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); }
        }

        public String ResPath
        {
            get
            {
                Configuration config = WebConfigurationManager.OpenWebConfiguration(
                    HttpContext.Current.Request.ApplicationPath == "/" ? "/IM" : HttpContext.Current.Request.ApplicationPath + "/IM"
                );

                return config.AppSettings.Settings["ResPath"].Value;
            }
        }

		public String GetResourceUrl(string path)
		{
            return String.Format("\"{0}/{1}\"", ResPath, path); ;
		}

		public String ReplaceVariable(string path)
		{
            path = path.Replace("{VERSION}", Version);
            path = path.Replace("{RESPATH}", ResPath);
			return path;
		}

		private object _logLock = new object();

		public void WriteLog(string text)
		{
			lock (_logLock)
			{
				string line = String.Format("[{0:yyyy-MM-dd hh:mm:ss}] {1}\r\n", DateTime.Now, text);
				System.IO.File.AppendAllText(_fileRoot + @"\trace.txt", line, Encoding.UTF8);
			}
		}

		public AccountInfo GetCurrentUser(HttpContext context)
		{
			return AccountImpl.Instance.GetUserInfo(GetUserName(context));
		}

		public String Debug
		{
			get
			{
#				if DEBUG
				return "true";
#				else
				return "false";
#				endif
			}
		}

		public String ServiceUrl
		{
			get
			{
				return _serviceUrl;
			}
		}
	}

	public class PermissionException : Exception
	{
		public PermissionException()
			: base("权限不足")
		{
		}
	}

	public class IOPermission
	{
		public const int Rename = 1;
		public const int Delete = 1 << 1;
		public const int Read = 1 << 2;
		public const int Write = 1 << 3;
	}
}
